package com.chen.demo.entity;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName StreamDemo.java
 * @Description TODO
 * @createTime 2023年04月27日 15:35:00
 */
public class StreamDemo {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
//        System.out.println(authors);
        /**
         * 需求1：我们可以调用getAuthors方法获取到到作家的集合。实现需要打印所有年龄小于18的作家的名字，并且要注意去重。
         * */
//        test02();
//        test03();
//        test04();
//        test06();
//        test07();
//        test08();
//        test09();
//        test10();
//        test11();
//        test12();
//        test13();
//        test14();
//        test15();
//        test18();
//        test19();
//        test20();
//        test21();
//        test22();
//        test23();
//        test24();
//        test25();
//        test26();
        test27();
    }


    /**
     *如果用一个参数的重载方法去求最小值代码如下：
     * */
    private static void test27(){
        List<Author> authors = getAuthors();
        Optional<Integer> reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result > element ? element : result;
                    }
                });
        reduce.ifPresent(age-> System.out.println(age));
    }

    /**
     *例三：使用reduce求所有作者中年龄的最小值
     * */

    private static void test26(){
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
        System.out.println(reduce);
    }


    /**
     * 例二：使用reduce求所有作者中年龄的最大值
     * */
    private static void test25(){
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
        System.out.println(reduce);
    }

    /**
     * 使用reduce求所有作者年龄的和
     * */
    private static void test24(){
        List<Author> authors = getAuthors();
        Integer sum = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result + element);
        System.out.println(sum);
    }

    /**
     *获取一个年龄最小的作家，并输出他的姓名
     * */
    private static void test23(){
        List<Author> authors = getAuthors();
        Optional<Author> optionalAuthor = authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
    }

    /**
     * 例子：获取任意一个大于18岁的作家，如果存在输出他的名字
     * */
    private static void test22(){
        List<Author> authors = getAuthors();
        Optional<Author> optionalAuthor = authors.stream()
                .filter(author -> author.getAge()>18)
                .findAny();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));

    }

     /**
      * 判断作家是否都没有超过100岁的
      * */
     public static void test21(){
         List<Author> authors = getAuthors();
         boolean b = getAuthors().stream()
                 .noneMatch(author -> author.getAge() >100);
         System.out.println(b);
     }

    /**
     * 判断是否所有的作家都是成年人
     * */
    private static void test20(){
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .allMatch(author -> author.getAge() >= 18);
        System.out.println(flag);
    }

    /**
     * 判断是否有年龄在29以上的作家
     * */
    private static void test19(){
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(flag);
    }

    /**
     * 例三：获取一个map集合，map的key为作者名，value为List
     * */
    private static void test18(){
        List<Author> authors = getAuthors();
        Map<String, List<Book>> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(map);
    }

    /**
     * 例二：获取一个所有书名的Set集合
     * */
    private static void test17(){
        List<Author> authors = getAuthors();
        Set<String> bookSet = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getName())
                .collect(Collectors.toSet());
        System.out.println(bookSet);
    }


    /**
     * 获取一个存放所有作者名字的List集合
     * */
    private static void test16(){
        List<Author> authors = getAuthors();
        List<String> nameList = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(nameList);
    }



    /**
     * 分别获取这些作家的所出书籍的最高分和最低分并打印
     * Stream<Author> ->Stream<Book> -> Stream<Integer> ->求值
     * */
    private static void test15(){
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .distinct()
                .max(((score1, score2) -> score1 - score2));

        Optional<Integer> min = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min((score1, score2) -> score1 - score2);
        System.out.println("最高分" + max.get());
        System.out.println("最低分" + min.get());
    }

    /**
     *例子：打印这些作家所出书籍的数目，注意删除重复元素
     * */
    private static void test14(){
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

    /**
     * 输出所有作家的名字
     * */
    private static void test13(){
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .distinct()
                .forEach(name -> System.out.println(name));
    }


    /**
     * 打印现有数据的所有分类。要求对分类进行去重。不能出现这样格式：哲学，爱情
     * */
    private static void test12(){
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(category-> System.out.println(category));

    }

    /**
     * 打印所有书籍的名字。要求对重复的元素进行去重。
     * */
    private static void test11(){
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));
    }

    /**
     * 打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
     * */
    private static void test10(){
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素，然后打印其中年龄最大的两个作家的姓名
     * */
    private static void test09(){
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .limit(2)
                .forEach(author-> System.out.println(author.getName()));

    }


    /**
     * 例如：对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素
     * */

    private static void test08(){
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .forEach(author -> System.out.println(author.getAge()));
    }


    /**
     * 打印所有作家的姓名，并且要求其中不能有重复元素
     * */
    private static void test07(){
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));
    }


    /**
     * 打印所有作家的姓名
     * */
    private static void test06(){
        List<Author> authors = getAuthors();
//        authors.stream()
////                .forEach(author -> System.out.println(author.getName()));
//                .map(author -> author.getName())
//                .forEach(s -> System.out.println(s));

        authors.stream()
                .map(author -> author.getAge())
                .map(age->age+10)
                .forEach(age-> System.out.println(age));
    }


    /**
     * 要求：打印所有姓名长度大于1的作家的姓名
     * */
    private static void test05(){
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length()>1)
                .forEach(System.out::println);
    }


    private static void test04() {
        Map<String, Integer> map = new HashMap<>();
        map.put("蜡笔小新", 5);
        map.put("zyy", 22);
        map.put("zqh", 23);
        //使用map方法的entrySet方法将其转换为set类型的集合
        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
        stream.distinct()
                .filter(entry -> entry.getValue() > 5)
                .forEach(entry -> System.out.println(entry.getKey() + "==" + entry.getValue()));
    }


    private static void test03() {
        Integer[] arr = {1, 2, 3, 4, 5};
        //第一种创建stream流的方式
        Stream<Integer> stream1 = Arrays.stream(arr);
        //第二种创建stream流的方式
        Stream<Integer> stream = Stream.of(arr);
        stream1.distinct()
                .filter(integer -> integer > 2)
                .forEach(integer -> System.out.println(integer));

        Stream<Integer> stream2 = Stream.of(arr);
        stream2.distinct()
                .filter(integer -> integer < 2)
                .forEach(integer -> System.out.println(integer));
    }



    /**
     * 优化前 匿名内部类的写法
     * */
    private static void test01() {
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
        //把集合转换成流
        stream
                //去重
                .distinct()
                //过滤条件
                .filter(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() < 18;
                    }
                })
                //打印
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName() + "今年" + author.getAge() + "岁");
                    }
                });
    }

    /**
     * 优化后的
     * */
    private static void test02() {
        List<Author> authors = getAuthors();
        //把集合转换成流
        authors.stream()
                //去重
                .distinct()
                //过滤条件
                .filter(author -> author.getAge() < 18)
                //打印
                .forEach(author -> System.out.println(author.getName() + "今年" + author.getAge() + "岁"));
    }


    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));

        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
        return authorList;
    }

}
